package com.gitee.feizns.quickstart.ding.talk.event;

import com.dingtalk.open.app.api.GenericEventListener;
import com.dingtalk.open.app.api.OpenDingTalkClient;
import com.dingtalk.open.app.api.OpenDingTalkStreamClientBuilder;
import com.dingtalk.open.app.api.security.AuthClientCredential;
import com.dingtalk.open.app.stream.protocol.event.EventAckStatus;
import com.gitee.feizns.dynamic.DateUtils;
import com.gitee.feizns.quickstart.ding.talk.Config;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 钉钉流事件监听器
 * @author feizns
 * @since 2025/3/24
 */
@Slf4j
public class DingTalkStreamEventListener {

    /**
     * 配置
     */
    public final Config config;

    /**
     * 事件侦听器
     */
    private final List<GenericEventListener> eventListeners = new ArrayList<>();

    /**
     * 事件侦听器
     */
    private final Map<String, List<GenericEventListener>> eventListenersMap = new ConcurrentHashMap<>();

    /**
     * 钉钉流事件监听器
     * @param config 配置
     */
    @SneakyThrows
    public DingTalkStreamEventListener(Config config) {
        this.config = config;
    }

    /**
     * 开始
     */
    @SneakyThrows
    public OpenDingTalkClient start() {
        OpenDingTalkClient client = OpenDingTalkStreamClientBuilder
                .custom()
                .credential(new AuthClientCredential(config.getAppKey(), config.getAppSecret()))
                .registerAllEventListener(event -> {
                    String now = DateUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS");
                    log.debug("[{}]:接收到钉钉事件[{}]：事件数据：[{}]", now, event.getEventType(), event);
                    try {
                        //全局监听器列表
                        eventListeners.forEach(listener -> listener.onEvent(event));
                        //指定监听器列表
                        List<GenericEventListener> listeners = eventListenersMap.getOrDefault(event.getEventType(), new ArrayList<>());
                        listeners.forEach(listener -> listener.onEvent(event));
                        return EventAckStatus.SUCCESS;
                    } catch (Exception e) {
                        log.error("[{}]:处理钉钉事件[{}]时发生异常：事件数据：[{}]", now, event.getEventType(), event, e);
                        e.printStackTrace();
                        return EventAckStatus.LATER;
                    }
                })
                .build();
        client.start();
        return client;
    }

    /**
     * 注册
     * @param eventListener 事件侦听器
     */
    public DingTalkStreamEventListener register(GenericEventListener eventListener) {
        eventListeners.add(eventListener);
        return this;
    }

    /**
     * 注册指定类型事件
     * @param eventListener 事件侦听器
     */
    public DingTalkStreamEventListener register(GenericEventListener eventListener, String... eventTypes) {
        Arrays.stream(eventTypes).forEach(eventType -> {
            List<GenericEventListener> listeners = eventListenersMap.getOrDefault(eventType, new ArrayList<>());
            listeners.add(eventListener);
            eventListenersMap.put(eventType, listeners);
        });
        return this;
    }

}
